package com.nextive.weightlogger.activity;

import static com.nextive.weightlogger.util.DateUtil.getFormattedDate;
import static com.nextive.weightlogger.util.DialogUtil.showMessage;
import static com.nextive.weightlogger.util.StringUtil.padLeft;
import static com.nextive.weightlogger.util.StringUtil.padRight;
import static com.nextive.weightlogger.util.StringUtil.validateEmailAddress;

import java.util.Calendar;
import java.util.List;

import android.app.AlertDialog;
import android.app.DatePickerDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.text.Html;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.DatePicker;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.nextive.weightlogger.R;
import com.nextive.weightlogger.dao.SettingsDao;
import com.nextive.weightlogger.dao.WeightLogDao;
import com.nextive.weightlogger.dto.Settings;
import com.nextive.weightlogger.dto.WeightEntry;
import com.nextive.weightlogger.util.ContentUtil;

/**
 * Lets the user pick a set of entries to share based on a start date, pick a
 * recipient and share this info using an external email client application.
 * 
 * @author Federico Baseggio <fedebaseggio@gmail.com>
 */
public class ShareActivity extends BaseActivity {
	/**
	 * The amount of space characters to use to separate columns in the weight
	 * entries table.
	 */
	private final int TABLE_PADDING = 1;

	/**
	 * Code to identify actions in {@link #onActivityResult(int, int, Intent)}
	 */
	private final int ACTIVITY_RESULT_CREATE = 2;
	
	private WeightLogDao dao;
	private SettingsDao settingsDao;
	private Settings settings;
	private TextView startField;
	private TextView recipientField;
	private Button shareButton;
	
	/**
	 * The start date for the range of entries to share, or all entries if null.
	 */
	private Calendar fromDate;
	
	private String recipientEmail;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		dao = new WeightLogDao(this);
		settingsDao = new SettingsDao(this);
		
		setContentView(R.layout.share);
		
		startField = (TextView) findViewById(R.id.startDateField);
		recipientField = (TextView) findViewById(R.id.recipientField);
		shareButton = (Button) findViewById(R.id.shareButton);

		LinearLayout startLayout = (LinearLayout) findViewById(R.id.startLayout);
		startLayout.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				promptForDateRange();
			}
		});

		LinearLayout recipientLayout = (LinearLayout) findViewById(R.id.recipientLayout);
		recipientLayout.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				promptForRecipientType();
			}
		});
		
		shareButton.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				share();
			}
		});
	}

	@Override
	protected void onResume() {
		super.onResume();

		settings = settingsDao.readSettings();
		if (recipientEmail == null)
		{
			recipientEmail = settings.getDefaultRecipientEmail();
			if (recipientEmail == null)
			{
				recipientEmail = settings.getEmail();
			}
		}
		updateDisplay();
	}
	
	/**
	 * Populates the display fields in the layout with the values selected.
	 */
	private void updateDisplay()
	{
		String fromDateString = getString(R.string.share_date_range_all);
		if (fromDate != null)
		{
			fromDateString = String.format(
					getString(R.string.share_date_range_since),
					getFormattedDate(fromDate));
		}
		startField.setText(fromDateString);
		recipientField.setText(recipientEmail);
	}
	
	/**
	 * Displays a dialog asking the user to pick either all entries or entries
	 * from a start date.
	 */
	private void promptForDateRange()
	{
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		
		builder.setTitle(R.string.share_date_range);

		// Dialog items
		String allEntries = getString(R.string.share_date_range_all);
		String sinceSpecificDate = getString(R.string.share_date_range_pick_start);
		CharSequence[] items = {allEntries, sinceSpecificDate};

		builder.setItems(items, new DialogInterface.OnClickListener() {
		    public void onClick(DialogInterface dialog, int item) {
		    	switch(item)
		        {
	        	case 0:
					// All entries
	        		fromDate = null;
					updateDisplay();
	        		break;
	        	case 1:
	        		// Pick a start date
	        		promptForStartDate();
	        		break;
		        }
		    }
		});
		AlertDialog alert = builder.create();
		alert.show();
	}
	
	/**
	 * Displays a dialog asking the user to pick a type of recipient, either
	 * himself, the default recipient that is set, or a new contact.
	 */
	private void promptForRecipientType()
	{
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		
		builder.setTitle(R.string.share_recipient_email);

		// Dialog items
		String self = getString(R.string.settings_recipient_self);
		String defaultRecipient = getString(R.string.settings_default_recipient_email);
		String newContact = getString(R.string.settings_recipient_new);
		CharSequence[] items = {self, defaultRecipient, newContact};
		
		builder.setItems(items, new DialogInterface.OnClickListener() {
		    public void onClick(DialogInterface dialog, int item) {
		    	switch(item)
		        {
	        	case 0:
	        		// Self
					recipientEmail = settings.getEmail();
					updateDisplay();
	        		break;
	        	case 1:
	        		// Default recipient
	        		recipientEmail = settings.getDefaultRecipientEmail();
					updateDisplay();
	        		break;
	        	case 2:
	        		// New contact
	        		promptForCreateContact();
	        		break;
		        }
		    }
		});
		AlertDialog alert = builder.create();
		alert.show();
	}
	
	/**
	 * Launches the create contact activity to capture the result.
	 */
	private void promptForCreateContact()
	{
		Intent intent = new Intent(Intent.ACTION_INSERT,
				ContactsContract.Contacts.CONTENT_URI);
		startActivityForResult(intent, ACTIVITY_RESULT_CREATE);
	}

	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
	    if(resultCode == RESULT_OK) {
	    	switch (requestCode)
	    	{
	    	case ACTIVITY_RESULT_CREATE:
	    		onContactPicked(data);
	    		break;
	    	}
	    }
	}
	
	/**
	 * Called after the user created a new contact.
	 * 
	 * Looks up the email address and stores the value in
	 * {@link #recipientEmail}.
	 * 
	 * @param data
	 *            The intent returned by the create contact activity.
	 */
	private void onContactPicked(Intent data) {
		ContentUtil contentUtil = new ContentUtil(getContentResolver());
		String emailAddress = contentUtil.getEmail(data.getData());
		if (emailAddress == null) {
			showMessage(this, R.string.settings_contact_no_email);
		} else if (!validateEmailAddress(emailAddress)) {
			showMessage(this, R.string.share_invalid_recipient_email);
		} else {
			recipientEmail = emailAddress;
			updateDisplay();
			promptMakeDefaultRecipient();
		}
	}
	
	/**
	 * Displays a dialog asking the user if the newly created contact will be
	 * the new default recipient. If so, the settings are updated accordingly. 
	 */
	private void promptMakeDefaultRecipient()
	{
		String question = String.format(
				getString(R.string.share_make_default_recipient),
				recipientEmail);

		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		
		builder.setTitle(R.string.settings_default_recipient_email);
		builder.setMessage(question);
		builder.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which) {
				settings.setDefaultRecipientEmail(recipientEmail);
				settingsDao.saveSettings(settings, settingsDao
								.getSettingsValid());
			}
		});
		builder.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which) {
				// Just let the dialog be dismissed.
			}
		});
		AlertDialog alert = builder.create();
		alert.show();
	}
	
	/**
	 * Retrieves the weight entries, generates the email and launches the email
	 * app.
	 */
	private void share() {
		List<WeightEntry> entries;
		if (fromDate == null) {
			entries = dao.readAll();
		} else {
			entries = dao.readFrom(fromDate);
		}

		if (!validateEmailAddress(recipientEmail)) {
			showMessage(this, R.string.share_invalid_recipient_email);
			return;
		}

		if (entries.size() == 0) {
			showMessage(this, R.string.share_no_entries);
			return;
		}

		String html = getTable(entries);
		startEmailActivity(recipientEmail, html);
	}
	
	/**
	 * Launches a DatePicker dialog for the user to pick the start date of the
	 * range of entries to share.
	 */
	private void promptForStartDate() {
		DatePickerDialog.OnDateSetListener onDateSetListener = new DatePickerDialog.OnDateSetListener() {
			@Override
			public void onDateSet(DatePicker view, int year, int monthOfYear,
					int dayOfMonth) {
				fromDate = Calendar.getInstance();
				fromDate.set(year, monthOfYear, dayOfMonth, 0, 0);
				updateDisplay();
			}
		};
		Calendar today = Calendar.getInstance();
		int year = today.get(Calendar.YEAR);
		int month = today.get(Calendar.MONTH);
		int day = today.get(Calendar.DAY_OF_MONTH);
		DatePickerDialog dialog = new DatePickerDialog(this, onDateSetListener,
				year, month, day);
		dialog.show();
	}
	
	/**
	 * Retrieves an HTML table containing the weight entries specified.
	 * 
	 * @param entries
	 *            The entries to populate the HTML table with.
	 * @return An HTML table containing the weight entries specified.
	 */
	private String getTable(List<WeightEntry> entries)
	{
		String dateTitle = getString(R.string.log_weight_date);
		String timeTitle = getString(R.string.log_weight_time);
		String weightTitle = getString(R.string.log_weight_weight);
		
		int maxDateWidth = dateTitle.length();
		int maxTimeWidth = timeTitle.length();
		int maxWeightWidth = weightTitle.length();
		
		for (WeightEntry entry : entries)
		{
			int dateWidth = entry.getDateForDisplay().length();
			int timeWidth = entry.getTimeForDisplay().length();
			int weightWidth = entry.getWeightForDisplay(settings.getUnit()).length();
			if (dateWidth > maxDateWidth)
			{
				maxDateWidth = dateWidth;
			}
			if (timeWidth > maxTimeWidth)
			{
				maxTimeWidth = timeWidth;
			}
			if (weightWidth > maxWeightWidth)
			{
				maxWeightWidth = weightWidth;
			}
		}

		StringBuilder html = new StringBuilder("<html xmlns=\"http://www.w3.org/1999/xhtml\">");
		html.append("<body>");
		html.append("<code>");
		html.append("<b>" + padRight(dateTitle, maxDateWidth) + "</b>");
		html.append("<b>" + padRight(timeTitle, maxTimeWidth) + "</b>");
		html.append("<b>" + padLeft(weightTitle, maxWeightWidth) + "</b>");
		for (WeightEntry entry : entries)
		{
			html.append("<br />");
			html.append(padRight(entry.getDateForDisplay(), maxDateWidth + TABLE_PADDING));
			html.append(padRight(entry.getTimeForDisplay(), maxTimeWidth + TABLE_PADDING));
			html.append(padLeft(entry.getWeightForDisplay(settings.getUnit()), maxWeightWidth));
		}
		html.append("</code>");
		html.append("</body>");
		html.append("</html>");
		return html.toString();
	}
	
	/**
	 * Starts an activity to send the e-mail.
	 * 
	 * @param to E-mail address of the recipient.
	 * @param html Body of the e-mail in HTML.
	 */
	private void startEmailActivity(String to, String html) {
		Intent intent = new Intent(Intent.ACTION_SEND);
		intent.setType("text/html");
		intent.putExtra(Intent.EXTRA_EMAIL, new String[] { to });
		intent.putExtra(Intent.EXTRA_SUBJECT, this
				.getString(R.string.share_email_subject));
		intent.putExtra(Intent.EXTRA_TEXT, Html.fromHtml(html));
		startActivity(Intent.createChooser(intent, this
				.getString(R.string.share_pick_email_app)));
	}
}
